#include "thread_pool.h"
#include "mysql/mysql.h"
#include "user.h"
#define EPOLL_ARR_SIZE 100

int exitPipe[2];
char server_wd[1024] = {0};

//存储已经登陆的客户信息
ListNode * userList = NULL;

void sigHandler(int num)
{
    printf("\n sig is coming.\n");
    //激活管道, 往管道中写一个1
    int one = 1;
    write(exitPipe[1], &one, sizeof(one));
}

void * threadFunc2(void* arg)
{
    thread_arg_t args = *(thread_arg_t*)arg;
    //绑定新端口处理puts/gets/quit命令
    int listenfd = tcpInit(args.ip,args.port);
    int peerfd = accept(listenfd, NULL, NULL);
    //先加入用户链表,暂时未实现token技术
    user_info * user =(user_info*) calloc(1,sizeof(user_info)); 
    user->peerfd = peerfd;
    printf("thread userpeerfd is %d\n",peerfd);
    strcpy(user->pwd,server_wd);
    puts(user->pwd);
    strcpy(user->pre_wd,server_wd);
    user->login_status = LOGIN_OUT;
    appendNode(&userList,user);
    
    //先接登录成功的用户名
    int len = 0;
    recvn(peerfd,&len,4);
    CmdType type = (CmdType)-1;
    recvn(peerfd,&type,4);
    char username[50];
    recvn(peerfd,username,len);
    printf("收到登录名为:%s\n",username);
    strcpy(user->name,username);
    select_user_changeid(user);
    printf("现在的uid是%d\n",user->user_id);
    //处理长命令 
    while(1){
        task_t task;
        memset(&task,0,sizeof(task));
        task.peerfd = peerfd;
        //接受命令并初始化task
        thread_HandleMessage(&task);
    }
}
int main(int argc, char ** argv)
{   
    //server.conf
    char ip[512] = {0};
    char port[512] = {0};
    int threadNum = 0;
    serverconf(argv[1],ip,port,&threadNum);
    //ip,port,threadNum
    printf("sizeof(CmdType):%lu\n", sizeof(CmdType));
    ARGS_CHECK(argc, 2);
    //创建匿名管道
    pipe(exitPipe);

    //记录第一次cd的初值
    getcwd(server_wd,sizeof(server_wd));
        

    //fork之后，将创建了子进程
    pid_t pid = fork();
    if(pid > 0) {//父进程
        close(exitPipe[0]);//父进程关闭读端
        signal(SIGUSR1, sigHandler);
        wait(NULL);//等待子进程退出，回收其资源
        close(exitPipe[1]);
        printf("\nparent process exit.\n");
        exit(0);//父进程退出
    }
    //子进程
    close(exitPipe[1]);//子进程关闭写端

    //创建一个子线程处理长命令
    thread_arg_t t_task;
    memset(&t_task,0,sizeof(t_task));
    strcpy(t_task.ip,ip);
    strcpy(t_task.port,"9999");
    pthread_t tid;
    if((pthread_create(&tid,NULL,threadFunc2,&t_task))!= 0 ){
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }

    threadpool_t threadpool;
    memset(&threadpool, 0, sizeof(threadpool));

    //初始化线程池
    threadpoolInit(&threadpool, threadNum);
    //启动线程池
    threadpoolStart(&threadpool);

    //创建监听套接字
    int listenfd = tcpInit(ip, port);

    //创建epoll实例
    int epfd = epoll_create1(0);
    ERROR_CHECK(epfd, -1, "epoll_create1");

    //对listenfd进行监听
    addEpollReadfd(epfd, listenfd);
    addEpollReadfd(epfd, exitPipe[0]);

    struct epoll_event * pEventArr = (struct epoll_event*)
        calloc(EPOLL_ARR_SIZE, sizeof(struct epoll_event));
    
    while(1) {
        int nready = epoll_wait(epfd, pEventArr, EPOLL_ARR_SIZE, -1);
        if(nready == -1 && errno == EINTR) {
            continue;
        } else if(nready == -1) {
            ERROR_CHECK(nready, -1, "epoll_wait");
        } else {
            //大于0
            for(int i = 0; i < nready; ++i) {
                int fd = pEventArr[i].data.fd;
                if(fd == listenfd) {//对新连接进行处理
                    int peerfd = accept(listenfd, NULL, NULL);
                    printf("\n conn %d has conneted.\n", peerfd);
                    //将新连接添加到epoll的监听红黑树上
                    addEpollReadfd(epfd, peerfd);
                    //增加用户节点信息
                    user_info * user = (user_info*) calloc(1,sizeof(user_info));
                    user->peerfd = peerfd;
                    strcpy(user->pwd,server_wd);
                    strcpy(user->pre_wd,server_wd);
                    user->login_status = LOGIN_OUT;
                    appendNode(&userList,user);
                    logCLientConnection(peerfd);
                } else if(fd == exitPipe[0]) {
                    //线程池要退出
                    int howmany = 0;
                    //对管道进行处理
                    read(exitPipe[0], &howmany, sizeof(howmany));
                    //主线程通知所有的子线程退出
                    threadpoolStop(&threadpool);
                    //子进程退出前，回收资源
                    threadpoolDestroy(&threadpool);
                    close(listenfd);
                    close(epfd);
                    close(exitPipe[0]);
                    printf("\nchild process exit.\n");
                    exit(0);
                } else {//客户端的连接的处理
                    handleMessage(fd, epfd, &threadpool.que);
                }
            }
        }
    }
    return 0;
}

